package com.hujing.springsource.a18;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

public class A18_1 {
    
    static class Target{
        public void foo(){
            System.out.println("Target.foo");
        }
    }
    
    static class Advice1 implements MethodInterceptor{
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before Advice1");
            Object result = invocation.proceed();
            System.out.println("after Advice1");
            return result;
        }
    }
    
    static class Advice2 implements MethodInterceptor{

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before Advice2");
            Object result = invocation.proceed();
            System.out.println("after Advice2");
            return result;
        }
    }
    
    static class MyInvocation implements MethodInvocation{
        private Object target;
        private Method method;
        private Object[] args;
        private List<MethodInterceptor> interceptors;
        private int count = 1;

        public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> interceptors) {
            this.target = target;
            this.method = method;
            this.args = args;
            this.interceptors = interceptors;
        }

        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return args;
        }

        @Override
        public Object proceed() throws Throwable {
            if (count > interceptors.size()){
                //调用目标并结束递归
                return method.invoke(target,args);
            }
            return interceptors.get(count++-1).invoke(this);
        }

        @Override
        public Object getThis() {
            return target;
        }

        @Override
        public AccessibleObject getStaticPart() {
            return null;
        }
    }

    public static void main(String[] args) throws Throwable {
        Target target = new Target();
        List<MethodInterceptor> list = Arrays.asList(new Advice1(), new Advice2());
        MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], list);
        invocation.proceed();
    }
}
